package cn.blnp.net.flowable.task.ext.mail;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * <h3>邮件任务整合演示案例</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/13 16:34
 */
@Slf4j
@SpringBootTest
public class MailTaskTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    /**
     *  <h2>邮件任务使用案例</h2>
     *  <p>
     *      顾名思义，邮件任务是用于发邮件的任务，Flowable支持通过自动邮件服务任务增强业务流程。流程流转到邮件任务时，可以向指定的一个或多个收信人发送邮件，同时支持cc（代表carbon copy，即抄送）、
     *  bcc（代表blind carbon copy，即密送），邮件内容还支持HTML格式。
     *  <pre>
     *      {@code
     *          <serviceTask id="mailTask1" name="邮件任务" flowable:type="mail" />
     *      }
     *  </pre>
     *  <ul>
     *      <li>to：</li>邮件接收者的邮箱地址。可以使用英文逗号分隔多个接收者的邮箱地址
     *      <li>from：</li>邮件发送人的邮箱地址。如果不提供，会使用默认配置的地址
     *      <li>subject：</li>邮件的主题
     *      <li>cc：</li>邮件抄送人的邮箱地址。可以使用英文逗号分隔多个抄送人邮箱地址
     *      <li>bcc：</li>邮件密送人的邮箱地址。可以使用英文逗号分隔多个密送人邮箱地址
     *      <li>charset：</li>用于指定邮件的字符集，对很多非英语语言是必须设置的
     *      <li>html：</li>邮件的HTML文本
     *      <li>text：</li>邮件的内容，用于纯文本邮件。对于不支持富文本内容的客户端，与html一起使用，邮件客户端可以降级为显式纯文本格式
     *      <li>htmlVar：</li>存储邮件HTML内容的流程变量名。与html属性的不同之处在于，这个属性会在邮件任务发送前，使用其内容进行表达式替换
     *      <li>textVar：</li>存储邮件纯文本内容的流程变量名。与text属性的不同之处在于，这个属性会在邮件任务发送前，使用其内容进行表达式替换
     *      <li>ignoreException：</li>当处理邮件失败时，是忽略还是抛出FlowableException。默认为false
     *      <li>exceptionVariableName：</li>当设置ignoreException = true，而处理邮件失败时，使用此属性指定名称的变量将保存失败信息
     *  </ul>
     *  </p>
     *  <p>
     *      关于邮件服务器的可配置属性主要有以下这些：
     *      <il>
     *          <li>mailServerHost：</li>邮件服务器的主机名（如mail.qq.com）。默认为localhost
     *          <li>mailServerPort：</li>邮件服务器上的SMTP传输端口。默认为25
     *          <li>mailServerDefaultFrom：</li>如果没有指定发送邮件的邮件地址，默认设置的发送者的邮件地址。默认为flowable@localhost
     *          <li>mailServerUsername：</li>视邮件服务器要求多数邮件服务器需要授权用户名才能发送邮件。默认不设置
     *          <li>mailServerPassword：</li>视邮件服务器要求多数邮件服务器需要授权用户名对应的密码才能发送邮件。默认不设置
     *          <li>mailServerUseSSL：</li>视邮件服务器要求部分邮件服务器需要SSL通信。默认为false
     *          <li>mailServerUseTLS：</li>视邮件服务器要求一些邮件服务器要求TLS通信（如Gmail）。默认为false
     *      </il>
     *  </p>
     *  <p>
     *      <b>流程定义文件：</b>{@link flow/mailTaskTest.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/13/682305523c9cd.png" /><br/>
     *      <b>用户收件结果：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/13/68230fd90a8af.png" />
     *  </p>
     **/
    @Test
    public void test() {
        Deployment deploy = repositoryService.createDeployment()
                .name("邮件任务演示案例")
                .addClasspathResource("flow/mailTaskTest.bpmn20.xml")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());
        //设置流程变量
        Map<String, Object> varMap = MapUtil.builder(new HashMap<String, Object>())
                .put("starterName", "安琪拉")
                .put("formName", "《如何呵护猫咪》的重要演讲！")
                .build();
        //查询人员盘点任务
        Task task = taskQuery.singleResult();
        log.info("当前任务为：{}", task.getName());
        taskService.complete(task.getId(), varMap);

        //查询历史流程实例
        HistoricProcessInstance hisProcInst = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(procInst.getId())
                .singleResult();
        if (hisProcInst.getEndTime() != null) {
            log.info("当前流程已结束，结束时间：{}", DateUtil.formatDateTime(hisProcInst.getEndTime()));
        }

        /**
         *  演示结果：
         * 2025-05-13 17:23:07.687  INFO 106536 --- [           main] c.b.n.f.task.ext.mail.MailTaskTest       : 部署流程定义：e153bd02-2fdb-11f0-80cb-50ebf6ec8f6d
         * 2025-05-13 17:23:07.691  INFO 106536 --- [           main] c.b.n.f.task.ext.mail.MailTaskTest       : 流程定义编号：e1886195-2fdb-11f0-80cb-50ebf6ec8f6d
         * 2025-05-13 17:23:07.740  INFO 106536 --- [           main] c.b.n.f.task.ext.mail.MailTaskTest       : 当前任务为：人员盘点
         * 2025-05-13 17:23:10.040  INFO 106536 --- [           main] c.b.n.f.task.ext.mail.MailTaskTest       : 当前流程已结束，结束时间：2025-05-13 17:23:09
         **/
    }
}
